package com.wang.common.util;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.BeanWrapper;
import org.springframework.beans.BeanWrapperImpl;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;

import java.beans.PropertyDescriptor;
import java.util.Arrays;
import java.util.Date;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;

/**
 * bean的工具类
 *
 * @author Wangsh
 */
@Component("beanUtil")
@Slf4j
public class BeanUtil {
    /**
     * 基本数据类型集合
     */
    private static final List<Class> BASE_TYPE_CLASS = Arrays.asList(
            Byte.class,Short.class,Integer.class,Long.class,Float.class,Double.class,Boolean.class,Character.class,
            byte.class,short.class,int.class,long.class,float.class,double.class,boolean.class,
            String.class, Date.class
        );
    /**
     * 引入的集合
     */
    private static final String FINAL_REF_KEY = "refList";
    private static final String FINAL_NULL_KEY = "nullList";

    /**
     * 拷贝属性
     * 如果源数据的对象不为空,直接赋值到目标对象中
     * 源对象和目标对象是一个类型(10个字段)
     * 源对象有5个字段有值,目标对象是10个有值
     * 把源对象中的5个字段有值,赋值到目标对象中.(覆盖)
     *
     * @param souObj 源对象
     * @param tarObj 目标对象
     * @return  目标对象
     */
    public Object copy(Object souObj, Object tarObj) {
        /* null值集合 */
        String[] noValuePropertyNames = this.getNullValuePropertyNames(souObj);
        log.info("拷贝对象,源对象:{},空值的字段集合:{}", souObj.getClass(), Arrays.toString(noValuePropertyNames));
        BeanUtils.copyProperties(souObj, tarObj, noValuePropertyNames);
        return tarObj;
    }

    /**
     * 获取对象中的 空值集合,对象也需要忽略
     *
     * @param source 源对象
     * @return 空值的字段集合
     */
    public String[] getNullValuePropertyNames(Object source) {
        /* set集合,不能重复 */
        Set<String> noValuePropertySet = new HashSet<>();
        Assert.notNull(source, "传递的参数对象不能为空");
        /* 获取bean的包装器 */
        BeanWrapper beanWrapper = new BeanWrapperImpl(source);
        /* 获取所有的属性描述 */
        PropertyDescriptor[] propertyDescriptorArr = beanWrapper.getPropertyDescriptors();
        for (PropertyDescriptor dataTemp : propertyDescriptorArr) {
            String propertyName = dataTemp.getName();
            Object propertyValue = beanWrapper.getPropertyValue(propertyName);
            /* 属性的类型 */
            Class<?> propertyType = beanWrapper.getPropertyType(propertyName);
            /* 不是基本类型,忽略拷贝 */
            if (!BASE_TYPE_CLASS.contains(propertyType)){
                noValuePropertySet.add(propertyName);
                continue;
            }
            if (Objects.isNull(propertyValue)) {
                noValuePropertySet.add(propertyName);
            } else {
                /* 是可迭代的集合 */
                if (Iterable.class.isAssignableFrom(propertyValue.getClass())) {
                    Iterable iterable = (Iterable) propertyValue;
                    Iterator iterator = iterable.iterator();
                    if (!iterator.hasNext()) {
                        noValuePropertySet.add(propertyName);
                    }
                }
                /* map集合 */
                if (Map.class.isAssignableFrom(propertyValue.getClass())) {
                    Map map = (Map) propertyValue;
                    if (map.isEmpty()) {
                        noValuePropertySet.add(propertyName);
                    }
                }
            }
        }
        String[] result = new String[noValuePropertySet.size()];
        return noValuePropertySet.toArray(result);
    }
}
